Skip to content

fix(android): initial measuring tweaks - #784

Merged
hejsztynx merged 9 commits into
mainfrom
@ksienkiewicz/fix-android-initial-measuring
Sep 3, 2026
Merged

fix(android): initial measuring tweaks#784
hejsztynx merged 9 commits into
mainfrom
@ksienkiewicz/fix-android-initial-measuring

Conversation

@hejsztynx

@hejsztynx hejsztynx commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

This fixes a bug where the component's initial height calculation would break if defaultValue was provided without an explicit fontSize in htmlStyle prop. The root cause was a mix of a bad initial estimate and invalid measurements caching:

During initialMeasure, missing a passed fontSize in props, meant it defaulted to 0, which caused the entire height estimate to be wrong. I fixed this by adding a fallback to the default font size, matching how EnrichedText measurements already handle it.

After initialMeasure, setValue (caused by the present defaultValue prop) is run, which tries to update the shadow node state, but stateWrapper is still null. This caused the MeasurementStore internal cache to be out of sync with the actual shadow node's state. Fixed this by providing an early return in invalidateLayout() - we don't call Measurement.store() at all, if stateWrapper is unavailable.

I've also tweaked two small things: in EnrichedTextInputShadowNode.cpp the forceHeightRecalculationCounter_ was never initialized before accessing its value, which would make it have random, garbage values. I've also adjusted the provided forceHeightRecalculationCounter to the stateWrapper, as its value was always pre-increment during invalidateLayout(). I believe it's better to have the shadow node's and component's counters' values consistent.

Sometimes the setValue's layout invalidation could run before the initialMeasure. That made the MeasurementStore cached measurements correct from the start, as after setValue runs, the actual component's size is measured, not estimated like it's the case with initialMeasure. You can see this race condition in the attached video.

Test Plan

I've provided a modified example app, so you can see the bug yourself - you can run

git checkout 212b2a3e

and then you can check out how it works after the fix

git checkout 4c478090

Screenshots / Videos

The race condition in action (stumbled across in a different app):

Screen.Recording.2026-08-27.at.12.12.20.mov

Compatibility

OS Implemented
iOS
Android
Web

Checklist

  • E2E tests are passing
  • Required E2E tests have been added (if applicable)

Copilot AI lite review requested due to automatic review settings August 27, 2026 10:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an Android-only race in initial height estimation for EnrichedTextInputView when defaultValue is set and fontSize is missing/invalid, by preventing MeasurementStore from caching “fresh” sizes until the shadow node can actually be invalidated.

Changes:

  • Default fontSize used during initialMeasure now falls back to the view’s default when fontSize is null or <= 0.
  • MeasurementStore.store now invalidates the shadow node via a callback and only commits the new cached size when invalidation succeeds.
  • Initializes forceHeightRecalculationCounter_ in the shadow node and aligns the counter value sent via state updates.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputShadowNode.h Initializes forceHeightRecalculationCounter_ to avoid undefined comparisons.
android/src/main/java/com/swmansion/enriched/textinput/MeasurementStore.kt Avoids caching new measured sizes unless shadow-node invalidation succeeds; improves fontSize fallback in initialMeasure.
android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewLayoutManager.kt Passes an invalidation callback into MeasurementStore.store and updates the state counter post-increment.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@hejsztynx
hejsztynx requested a review from exploIF August 27, 2026 11:52
Comment thread android/src/main/java/com/swmansion/enriched/textinput/MeasurementStore.kt Outdated
@exploIF

exploIF commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Could you provide human readable description? I've tried reading that, but completely lost the plot after 3rd sentence

@hejsztynx

Copy link
Copy Markdown
Collaborator Author

Could you provide human readable description? I've tried reading that, but completely lost the plot after 3rd sentence

Tried rewriting that. Previously, maybe I tried to put too much technical details there

@hejsztynx
hejsztynx requested a review from exploIF September 2, 2026 09:16
@hejsztynx
hejsztynx merged commit 55002b1 into main Sep 3, 2026
8 checks passed
@hejsztynx
hejsztynx deleted the @ksienkiewicz/fix-android-initial-measuring branch September 3, 2026 20:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants